﻿/*****************************************介绍*****************************************
 * 作者：Ywh
 * 创建时间：2023-05-09　11:11:15
 * 功能：UI实用类
**************************************************************************************/

using Game.Framework;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.UI;

public static partial class UIUtility
{
    #region 鼠标相关

    public static bool IsPointInRectTransform(RectTransform rect, Vector2 point)
    {
        Vector3[] worldCorners = new Vector3[4];
        rect.GetWorldCorners(worldCorners);

        return point.x >= worldCorners[0].x &&
               point.x <= worldCorners[3].x &&
               point.y >= worldCorners[0].y &&
               point.y <= worldCorners[1].y;
    }

    public static bool IsPointerInUI()
    {
        if (EventSystem.current == null) return false;
        return EventSystem.current.IsPointerOverGameObject();
    }

    public static bool IsLeftPointer(PointerEventData eventData)
    {
        return eventData.pointerId == -1;
    }

    public static bool IsRightPointer(PointerEventData eventData)
    {
        return eventData.pointerId == -2;
    }

    public static bool IsMiddlePointer(PointerEventData eventData)
    {
        return eventData.pointerId == -3;
    }

    /// <summary>
    /// 获取鼠标停留处UI
    /// </summary>
    /// <param name="canvas"></param>
    /// <returns></returns>
    public static GameObject GetOverUI(GameObject canvas)
    {
        PointerEventData pointerEventData = new PointerEventData(EventSystem.current);
        pointerEventData.position = Input.mousePosition;
        GraphicRaycaster gr = canvas.GetComponent<GraphicRaycaster>();
        List<RaycastResult> results = new List<RaycastResult>();
        gr.Raycast(pointerEventData, results);
        if (results.Count != 0)
        {
            return results[0].gameObject;
        }

        return null;
    }

    #endregion

    #region 面板相关

    /// <summary>检测指定界面是否为打开状态，如果是则关闭</summary>
    public static void CheckAndClosePanle(string mediatorName)
    {
        var state = PanelManager.Instance.GetPanelState(mediatorName);
        if (state == PanelState.Show)
            PanelManager.Instance.HidePanel(mediatorName);
    }

    /// <summary>检测指定界面是否为打开状态，如果是则处理一些列事情</summary>
    public static void CheckOpenAndDoSomething(string mediatorName, Action handler)
    {
        var state = PanelManager.Instance.GetPanelState(mediatorName);
        if (state == PanelState.Show)
            handler?.Invoke();
    }

    /// <summary>置顶显示某个UI对象</summary>
    public static void DisplayTopObj(GameObject target, bool isTop)
    {
        if (target == null) return;
        var canvas = target.GetComponent<Canvas>();
        var graphic = target.GetComponent<GraphicRaycaster>();
        if (isTop)
        {
            if (!canvas) canvas = target.AddComponent<Canvas>();
            if (!graphic) graphic = target.AddComponent<GraphicRaycaster>();
            canvas.overrideSorting = true;
            canvas.sortingOrder = 99;
            graphic.ignoreReversedGraphics = true;
        }
        else
        {
            if (graphic) UnityEngine.Object.Destroy(graphic);
            if (canvas) UnityEngine.Object.Destroy(canvas);
        }
    }

    public static T GetPanel<T>(string key) where T : BasePanel
    {
        return PanelManager.Instance.GetPanel<T>(key);
    }

    /// <summary>打开/隐藏指定界面（没有则创建）</summary>
    public static void DisplayPanel(string key, string path, UIRoot root = UIRoot.Canvas, object data = null)
    {
        PanelManager.Instance.DisplayPanel(key, path, root, data);
    }

    /// <summary>打开已经创建好的界面</summary>
    public static void ShowPanel(string key, object data = null)
    {
        PanelManager.Instance.ShowPanel(key, data);
    }

    /// <summary>
    /// 显示UI面板
    /// <para>如果不存在则创建</para>
    /// <para>如果存在并且已隐藏则打开</para>
    /// <para>如果存在并且已显示则不操作</para>
    /// </summary>
    public static void ShowPanel(string key, string path, UIRoot root = UIRoot.Canvas, object data = null)
    {
        var tipPanleStatus = GetPanelState(key);
        if (tipPanleStatus == PanelState.None)
            DisplayPanel(key, path, root, data);
        else if (tipPanleStatus == PanelState.Hide)
            ShowPanel(key, data);
    }

    /// <summary>关闭指定界面</summary>
    public static void HidePanel(string key)
    {
        PanelManager.Instance.HidePanel(key);
    }

    /// <summary>销毁指定界面</summary>
    public static void DestroyPanel(string key)
    {
        PanelManager.Instance.DestroyPanel(key);
    }

    /// <summary>获取指定界面的状态</summary>
    public static PanelState GetPanelState(string key)
    {
        return PanelManager.Instance.GetPanelState(key);
    }

    /// <summary>快速显示一个Toast</summary>
    public static void ShowToast(string tip)
    {
        DisplayPanel(Game.UI.ToastPanel.ToastPanelView.PANEL_KEY, "UI/ToastPanel/Prefabs/ToastPanel", UIRoot.Top, tip);
    }

    /// <summary>设置置顶显示大厅的部分UI</summary>
    public static void TopDisplayLobbyPanelInfo(bool isTopShow, bool coin, bool star = false)
    {
        var panel = GetPanel<Game.UI.HallPanel.HallPanelView>(Game.UI.HallPanel.HallPanelView.PANEL_KEY);
        if (panel) panel.TopDisplayInfos(isTopShow, coin, star);
    }

    #endregion

    #region 画布相关

    private static RectTransform canvasRect;
    private static CanvasScaler canvasScaler;

    private static void Find()
    {
        var canvasObj = GameObject.Find("Canvas");
        canvasRect = canvasObj.transform as RectTransform;
        canvasScaler = canvasObj.GetComponent<CanvasScaler>();
    }

    /// <summary>设置全局的UI交互状态</summary>
    public static void SetGlobalInteractive(bool isInteractive = true)
    {
        CanvasRect.GetComponent<GraphicRaycaster>().enabled = isInteractive;
        LogManager.Log($"设置全局的交互状态：{(isInteractive ? "可交互" : "不可交互")}");
    }

    /// <summary>
    /// UI拖拽比率，适用的缩放模式
    /// <para><see cref="CanvasScaler.ScaleMode.ConstantPixelSize"/></para>
    /// <para><see cref="CanvasScaler.ScaleMode.ScaleWithScreenSize"/>，<see cref="CanvasScaler.ScreenMatchMode.Expand"/>，<see cref="CanvasScaler.ScreenMatchMode.Shrink"/></para>
    /// </summary>
    public static float UIRate
    {
        get
        {
            float finalRate = -1;

            switch (CanvasScaler.uiScaleMode)
            {
                case CanvasScaler.ScaleMode.ConstantPixelSize:
                    finalRate = 1 / CanvasScaler.scaleFactor;
                    break;
                case CanvasScaler.ScaleMode.ScaleWithScreenSize:
                    switch (CanvasScaler.screenMatchMode)
                    {
                        case CanvasScaler.ScreenMatchMode.Expand:
                            // 哪个在变就计算哪个的比值
                            finalRate = CanvasWidth < CanvasScaler.referenceResolution.x ? CanvasHeight / Screen.height : CanvasWidth / Screen.width;
                            break;
                        case CanvasScaler.ScreenMatchMode.Shrink:
                            // 哪个在变就计算哪个的比值
                            finalRate = CanvasWidth > CanvasScaler.referenceResolution.x ? CanvasHeight / Screen.height : CanvasWidth / Screen.width;
                            break;
                        default:
                            LogManager.LogError($"当前比值不支持该UI屏幕匹配模式：screenMatchMode:{CanvasScaler.screenMatchMode}，请使用UIUtility.UIRate_Vector", "UIUtility");
                            break;
                    }
                    break;
                default:
                    LogManager.LogError($"当前比值不支持该UI缩放模式：uiScaleMode:{CanvasScaler.uiScaleMode}，请使用UIUtility.UIRate_Vector", "UIUtility");
                    break;
            }

            return finalRate;
        }
    }

    /// <summary>
    /// UI拖拽比率，适用的缩放模式
    /// <para><see cref="CanvasScaler.ScaleMode.ScaleWithScreenSize"/>，<see cref="CanvasScaler.ScreenMatchMode.MatchWidthOrHeight"/></para>
    /// <para><see cref="CanvasScaler.ScaleMode.ConstantPhysicalSize"/></para>
    /// </summary>
    public static Vector2 UIRate_Vector
    {
        get
        {
            Vector2 result = new Vector2(-1, -1);
            switch (CanvasScaler.uiScaleMode)
            {
                case CanvasScaler.ScaleMode.ScaleWithScreenSize:
                    switch (CanvasScaler.screenMatchMode)
                    {
                        case CanvasScaler.ScreenMatchMode.MatchWidthOrHeight:
                            result.x = CanvasWidth / Screen.width;
                            result.y = CanvasHeight / Screen.height;
                            break;
                        default:
                            LogManager.LogError($"当前比值不支持该UI屏幕匹配模式：screenMatchMode:{CanvasScaler.screenMatchMode}，请使用UIUtility.UIRate", "UIUtility");
                            break;
                    }
                    break;
                case CanvasScaler.ScaleMode.ConstantPhysicalSize:
                    result.x = CanvasWidth / Screen.width;
                    result.y = CanvasHeight / Screen.height;
                    break;
                default:
                    LogManager.LogError($"当前比值不支持该UI缩放模式：uiScaleMode:{CanvasScaler.uiScaleMode}，请使用UIUtility.UIRate", "UIUtility");
                    break;
            }
            return result;
        }
    }

    public static RectTransform CanvasRect
    {
        get
        {
            if (canvasRect == null) Find();
            return canvasRect;
        }
    }

    public static CanvasScaler CanvasScaler
    {
        get
        {
            if (canvasScaler == null) Find();
            return canvasScaler;
        }
    }

    /// <summary>获取画布的宽</summary>
    public static float CanvasWidth => CanvasRect.rect.width;

    /// <summary>获取画布的高</summary>
    public static float CanvasHeight => CanvasRect.rect.height;

    #endregion

    /// <summary>创建合适比例的RenderTexture，主要用于视频播放/小地图渲染</summary>
    public static RenderTexture CreateRenderTex()
    {
        RenderTexture tex = new RenderTexture((int)CanvasWidth, (int)CanvasHeight, GraphicsFormat.R8G8B8A8_UNorm, GraphicsFormat.D32_SFloat_S8_UInt);
        tex.dimension = TextureDimension.Tex2D;
        tex.antiAliasing = 8;
        tex.depth = 32;
        return tex;
    }

    /// <summary>计算等比缩放填充限制尺寸（可能超出边界）</summary>
    public static (float width, float height) CalcSizeToFill(float maxWidth, float maxHeight, float width, float height)
    {
        float widthRatio = maxWidth / width;
        float heightRatio = maxHeight / height;
        float scaleRatio = Mathf.Max(widthRatio, heightRatio);

        float newWidth = width * scaleRatio;
        float newHeight = height * scaleRatio;

        return (newWidth, newHeight);
    }

    /// <summary>计算等比缩放填充限制尺寸（可能超出边界）</summary>
    public static (float width, float height) CalcSizeToFill(RectTransform maxRect, Texture tex)
    {
        return CalcSizeToFill(maxRect.rect.width, maxRect.rect.height, tex.width, tex.height);
    }

    /// <summary>计算等比缩放适应限制尺寸（始终保持完整显示）</summary>
    public static (float width, float height) CalcSizeToFit(float maxWidth, float maxHeight, float width, float height)
    {
        float widthRatio = maxWidth / width;
        float heightRatio = maxHeight / height;
        float scaleRatio = Mathf.Min(widthRatio, heightRatio);

        float newWidth = width * scaleRatio;
        float newHeight = height * scaleRatio;

        return (newWidth, newHeight);
    }

    /// <summary>计算非安全区域的距离（单位：像素）</summary>
    public static (float top, float bottom) CalculateSafeAreaMargins()
    {
        // 获取屏幕安全区域
        Rect safeArea = Screen.safeArea;

        // 计算安全区域到屏幕顶部的距离（像素）
        float topMargin = Screen.height - (safeArea.y + safeArea.height);

        // 计算安全区域到屏幕底部的距离（像素）
        float bottomMargin = safeArea.y;

        LogManager.Log($"安全区域到顶部的距离: {topMargin} 像素", "安全区域信息");
        LogManager.Log($"安全区域到底部的距离: {bottomMargin} 像素", "安全区域信息");
        LogManager.Log($"屏幕总高度: {Screen.height} 像素", "安全区域信息");
        LogManager.Log($"安全区域高度: {safeArea.height} 像素", "安全区域信息");
        return (topMargin, bottomMargin);
    }

    #region 部分UI业务逻辑相关

    public static void ShowIntAdPanel()
    {
        //if (!GameDataMgr.Instance.IsPurchased_RemoveAds() && GameDataMgr.Instance.IsAchieveMergeMaxCount())
        //{
        //    DisplayPanel(Game.UI.IntAdPanel.IntAdPanelView.PANEL_KEY, "UI/IntAdPanel/Prefabs/IntAdPanel");
        //    GameDataMgr.Instance.ResetMergeCount();
        //    LogManager.Log($"触发倒计时插屏，打开倒计时界面");
        //}
    }

    #endregion
}